#define _CRT_SECURE_NO_WARNINGS

#include <Windows.h>
#include <stdio.h>

#include "sparse_node.h"

int sparse_node::write_file(HANDLE h_in_file, char *out_file_name)
{
	HANDLE h_out_file;
	u8 buffer[1024];
	DWORD num_read, num_written;
	u64 total_written = 0;

	h_out_file = CreateFile(out_file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (h_out_file == INVALID_HANDLE_VALUE) {
		errmsg("create file %s failed: %s\n", out_file_name, last_error(msg_buf, MSG_BUF_SIZE));
		return -1;
	}
	if (seek_file(h_in_file, (__int64)start_pos, FILE_BEGIN) < 0){
		CloseHandle(h_out_file);
		return -1;
	}
	while (ReadFile(h_in_file, buffer, 1024, &num_read, NULL) && num_read > 0 && total_written < data_length) {
		WriteFile(h_out_file, buffer, num_read, &num_written, NULL);
		if (num_written != num_read) {
			errmsg("WriteFile error: %s\n", last_error(msg_buf, MSG_BUF_SIZE));
			CloseHandle(h_out_file);
			return -1;
		}
		total_written += num_written;
	}
	
	CloseHandle(h_out_file);

	return 0;
}

sparse_node_factory& sparse_node_factory::get_instance()
{
	static sparse_node_factory instance;

    return instance;
}

int sparse_node_factory::init(xml_node *part_node) {
	string value;
	part_node->get_val("SECTOR_SIZE_IN_BYTES", value);
	if (!value.empty()) {
		part_node->get_val("partofsingleimage", value);
		if (!value.empty()) {
			version = V2;
		} else {
			version = V3;
		}
	} else {
		version = V1;
	}
	return version;
}

sparse_node* sparse_node_factory::new_sparse_node(u64 s, u64 l, u64 b, u64 sa)
{
	switch (version) {
	case V1:
		return new sparse_node_v1(s, l, b, sa);
		break;
	case V2:
		return new sparse_node_v2(s, l, b, sa);
		break;
	case V3:
		return new sparse_node_v3(s, l, b, sa);
		break;
	}
	return NULL;
}

bool sparse_node_factory::is_first_node(const char *filename, const char *label)
{
	char buf[128];
	
	switch (version) {
	case V1:
		sprintf(buf, sparse_node_v1::static_get_file_fmt(), label, 1);
		break;
	case V2:
		sprintf(buf, sparse_node_v2::static_get_file_fmt(), label, 1);
		break;
	case V3:
		sprintf(buf, sparse_node_v3::static_get_file_fmt(), label, 1);
		break;
	}

	return strcmp(buf, filename) == 0;
}
